﻿using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.ServiceProcess;
using Microsoft.Win32;
using System.Net;
using OrbClientCacheService.Librarys;

namespace OrbClientCacheService
{
	public partial class CrmClientCacheService : ServiceBase
	{
		private CrmClientCacherSettings settings;

		private CrmClientCacherParams parameters;

		private RegistryKey appKey;

		private RegistryKey crmKey;

		public CrmClientCacheService()
		{
			this.InitializeComponent();

			if (!System.Diagnostics.EventLog.SourceExists("OrbClientCacheService"))
			{
				System.Diagnostics.EventLog.CreateEventSource("OrbClientCacheService", "CacheLog");
			}

			this.eventLog.Source = "OrbClientCacheService";
			this.eventLog.Log = "CacheLog";
		}

		protected override void OnStart(string[] args)
		{
			this.eventLog.WriteEntry("Service startup (onStart)", EventLogEntryType.Information);
			System.Diagnostics.Debugger.Launch();

			this.InitializeCacher();

			if (this.settings.FirstRun)
			{
				this.IndexClientAspx(this.parameters.InstallPath);
			}
		}

		protected override void OnStop()
		{
			this.eventLog.WriteEntry("Service shutdown (onStop)", EventLogEntryType.Information);
		}

		private void InitializeCacher()
		{
			// Standardeinstellungen und App-RegistryKey laden
			this.settings = CrmClientCacherSettings.DefaultCrmClientCacherSettings();
			this.appKey = Registry.LocalMachine.CreateSubKey(@"SOFTWARE\ORBIS AG\OrbClientCache");

			// FirstRun aus Registry lesen
			this.settings.FirstRun = this.GetSetValue<bool>(this.appKey, "FirstRun", this.settings.FirstRun, true);

			this.ReadCrmConfig();
		}

		private void ReadCrmConfig()
		{
			using (new Impersonator("administrator", "mscrm50dev", "crm"))
			{

				// CRM Parameter laden
				this.crmKey = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\MSCRMClient");
				if (this.crmKey == null)
					this.StopAndLog("Missing MSCRM installation or at least Registry-Key", EventLogEntryType.Error);

				// Installationspfad aus der Registry lesen
				this.parameters.InstallPath = this.GetSetValue<string>(this.crmKey, "InstallPath", null);
				if (this.parameters.InstallPath == null)
					this.StopAndLog("Missing \"InstallPath\" value on MSCRMClient Key", EventLogEntryType.Error);

			}
		}

		private void StopAndLog(string message, EventLogEntryType type)
		{
			this.eventLog.WriteEntry(message, type);
			this.Stop();
		}
		
		private void IndexClientAspx(string sDir)
		{
			// Wächter bricht ab, wenn ungültige übergabe
			if (sDir == null) return;

			// Durchlaufen der Verzeichnisstruktur
			try
			{
				foreach (string dir in Directory.GetDirectories(sDir))
				{
					foreach (string file in Directory.GetFiles(dir, "*.aspx"))
					{
						this.parameters.AspxIndex.Add(file);
					}

					// Rekursion
					this.IndexClientAspx(dir);
				}
			}
			catch (Exception e)
			{
				this.eventLog.WriteEntry(e.Message, EventLogEntryType.Error);
			}
		}
		
		/// <summary>
		/// Liest einen Wert aus der Registry und Versucht eine Typkonvertierung in den übergebenen Typ. Existiert ein
		/// Wert nicht, dann wird der Standardwert übernommen. Gegebenenfalls kann der Wert in der Registry mit dem
		/// Standardwert erstellt werden.
		/// </summary>
		/// <typeparam name="TReturn">Der Datentyp des Registry-Wertes</typeparam>
		/// <param name="key">Der Registry-Key unter dem der Wert gesucht werden soll</param>
		/// <param name="valueId">Der Schlüssel des Wertes der gesucht ist</param>
		/// <param name="def">Der Standard-Rückgabewert für diesen Schlüssel</param>
		/// <param name="setIfUnset">Wenn true, dann wird der Wert mit dem Standardwert erstellt</param>
		/// <returns>Den Inhalt des Wertes oder den Standardwert</returns>
		private TReturn GetSetValue<TReturn>(RegistryKey key, string valueId, TReturn def, bool setIfUnset = false)
		{

			object value = key.GetValue(valueId);

			if (value == null)
			{
				if (setIfUnset)	key.SetValue(valueId, def);
				value = def;
			}

			return (TReturn)Convert.ChangeType(value, typeof(TReturn));
		}

		private bool SubKeyExists(string subKey)
		{

			RegistryKey key = Registry.LocalMachine.OpenSubKey(subKey);
			
			if (key != null)
				return true;

			return false;
		}
	}

	public struct CrmClientCacherParams
	{

		public string InstallPath { get; set; }

		public string CassiniPort { get; set; }

		public string CrmClientVersion { get; set; }

		public ArrayList AspxIndex { get; set; }

	}

	public struct CrmClientCacherSettings
	{
		public bool FirstRun { get; set; }

		public int Timer { get; set; }

		// Konstruktor initialisiert Standardwerte
		public static CrmClientCacherSettings DefaultCrmClientCacherSettings()
		{
			CrmClientCacherSettings settings = new CrmClientCacherSettings();

			settings.FirstRun = true;
			settings.Timer = 60;

			return settings;
		}
	}
}
